
#ifndef __INKLUDE_C_DATA_PACKER_H__
#define __INKLUDE_C_DATA_PACKER_H__

#include <Inklude/Inklude.h>
#include <string>

namespace Inklude
{
/** @class	CDataPacker CDataPacker.h
*	@brief	It pack and unpack the data for network transfer.
*           You can pack and unpack any primitive type data and string (also wstring)
*           in one character array.
*           This class is singleton.
*	@since	0.1
*	@addtogroup TILE
*	@author Seokhwan Kim
*/
class INKLUDE_CLASS_EXPORT ikCDataPacker
{
public:
    ikCDataPacker() {}
    /**	@fn     template <typename T> int PackData(char* Buffer, int BufferSize, T Data)
	*	@brief	Pack data to Buffer
	*	@param	T data type
    *           Buffer character buffer storing data
    *           BufferSize the size of Buffer
    *           Data the T type data
    *   @return the size of packed data
    *	@since	0.1
    *	@author Seokhwan Kim
	*/
    template <typename T> 
    static int PackData(char* Buffer, int BufferSize, T Data);

    /**	@fn     template <typename T> int UnpackData(char*Buffer, int BufferSize, T* Data)
	*	@brief	Unpack data in Buffer
	*	@param	T data type
    *           Buffer character buffer containg data
    *           BufferSize the size of Buffer
    *           Data the T type data that store the unpacked
    *   @return the size of unpacked data
    *	@since	0.1
    *	@author Seokhwan Kim
	*/
    template <typename T> 
    static int UnpackData(char*Buffer, int BufferSize, T* Data);

    /**	@fn     template <typename T> int GetDataSize(T Data)
	*	@brief	Return the size of type T
	*	@param	T data type
    *   @return the size of type T
    *	@since	0.1
    *	@author Seokhwan Kim
	*/

    template <typename T> 
    static int GetDataSize(T Data);
    static bool CheckSize(int DataSize, int BufferSize);
};

template <typename T> 
int ikCDataPacker::PackData(char* Buffer, int BufferSize, T Data)
{
    int _typeSize = GetDataSize<T>(Data);

    if (CheckSize(_typeSize, BufferSize))
    {
        char* _ptrData = reinterpret_cast<char*>(&Data);
        memcpy_s(Buffer, BufferSize, _ptrData, _typeSize);
        return _typeSize;
    }

    return false;
}

template <typename T> 
int ikCDataPacker::UnpackData(char*Buffer, int BufferSize, T* Data)
{
    int _typeSize = GetDataSize<T>(*Data);

    if (CheckSize(_typeSize, BufferSize))
    {
        char* _ptrData = reinterpret_cast<char*>(Data);
        memcpy_s(_ptrData, _typeSize, Buffer, _typeSize);
    }
    return _typeSize;
}

template <typename T> 
int ikCDataPacker::GetDataSize(T Data)
{
    return sizeof(Data);
}

template <>
int ikCDataPacker::PackData<std::string>(char* Buffer, int BufferSize, std::string Data);

template<>
int ikCDataPacker::UnpackData<std::string>(char* Buffer, int BufferSize, std::string* Data);

template<>
int ikCDataPacker::PackData<std::wstring>(char* Buffer, int BufferSize, std::wstring Data);

template<>
int ikCDataPacker::UnpackData<std::wstring>(char* Buffer, int BufferSize, std::wstring* Data);

} // namespace Inklude

extern Inklude::ikCDataPacker g_dataPacker;

#endif // __INKLUDE_C_DATA_PACKER_H__

